<?php

/**
 * Created By PhpStorm
 * User sclecon
 * Contact Email 27941662@qq.com
 * Time 2021/9/7 16:24
 */
namespace wowo\Db;


class DbBase
{
    protected $table;
    protected $data;
    protected $where = [];
    protected $field;
    protected $order;
    protected $group;
    protected $limit;
    protected $pk = 'id';
    protected $last;

    private $condition_array = ['in', 'not in'];

    public function exec($sql, array $params = []){
        return \DB::query($sql, $params);
    }

    public function query($sql, array $params = []){
        return \DB::fetch_all($sql, $params);
    }

    public function data(array $data){
        $this->data = $data;
        return $this;
    }

    public function setPk($pk){
        $this->pk = $pk;
        return $this;
    }

    public function where($data, $condition = false, $value = false, $type = 'and'){
        $conditions = [];
        if (is_string($data) and in_array($condition, $this->condition_array) and is_array($value)){
            $conditions[] = ['key'=>$data, 'condition'=>$condition, 'value'=>'('.implode(',', $value).')'];
        }else if (is_string($data) and is_string($condition) and (is_string($value) or is_int($value))){
            $conditions[] = ['key'=>$data, 'condition'=>$condition, 'value'=>$value];
        }else if(is_string($data) and is_string($condition) or is_int($condition)){
            $conditions[] = ['key'=>$data, 'condition'=>'=', 'value'=>$condition];
        }else if(is_string($data)){
            $conditions[] = $data;
        }else if(is_array($data)){
            foreach ($data as $key => $datum){
                if (is_array($datum)){
                    foreach ($datum as $_key => $_value){
                        $conditions[] = ['key'=>$_key, 'condition'=>'=', 'value'=>$_value];
                    }
                }else{
                    $conditions[] = ['key'=>$key, 'condition'=>'=', 'value'=>$datum];
                }
            }
        }
        $condition = ['type'=>in_array($type, ['and', 'or'])?$type:'and', 'condition'=>$conditions];
        if (in_array($condition, $this->where) === false){
            $this->where[] = $condition;
        }
        return $this;
    }

    public function getLast(){
        return $this->last;
    }

    public function field($string){
        $this->field = $string;
        return $this;
    }

    public function order($field, $order = 'desc'){
        $this->order = ['key'=>$field, 'order'=>$order];
        return $this;
    }

    public function group($field){
        $this->group = $field;
        return $this;
    }

    public function table($table){
        $this->table = $table;
        $this->where = [];
        return $this;
    }

    public function limit($start, $number = false){
        $this->limit = ($start and $number === false) ? ['start'=>0, 'number'=>$start] : ['start'=>$start, 'number'=>$number];
        return $this;
    }

    protected function structure(){
        if (!$this->table){ throw new \Exception('table is null');}
        $params = [$this->field?:'*',$this->table];
        $order = $group = $limit = '';
        $condition = $this->getWhereStructure($params);
        if (is_array($this->order) and in_array('key', array_keys($this->order)) and in_array('order', array_keys($this->order))){
            $order = ' order by %i %i';
            $params[] = $this->order['key'];
            $params[] = $this->order['order'];
        }
        if ($this->group){
            $group = ' group by %i';
            $params[] = $this->group;
        }
        if (is_array($this->limit) and in_array('start', array_keys($this->limit)) and in_array('number', array_keys($this->limit))){
            $limit = ' limit %d,%d';
            $params[] = $this->limit['start'];
            $params[] = $this->limit['number'];
        }
        $sql = 'select %i from %t'.$condition.$order.$group.$limit;
        $this->initDb(['sql'=>$sql, 'params'=>$params]);
        return ['sql'=>$sql, 'params'=>$params];
    }

    protected function structureInsert(){
        if (!$this->table){ throw new \Exception('table is null');}
        $fields = [];
        foreach ($this->data as $item){
            if (is_array($item)){
                if (!$fields){
                    $fields = array_merge(array_keys($item));
                }
                $values[] = array_values($item);
            }else{
                $fields = array_merge(array_keys($this->data));
                $values[] = array_values($this->data);
                break;
            }
        }
        $valueString = $fieldString = '';
        foreach ($values as $value){
            $valueString .= (strlen($valueString) ? ', ': '').'(\''.implode("','", $value).'\')';
        }
        $fieldString = '(`'.implode("`,`", $fields).'`)';
        $sql = str_replace(['{table}', '{field}', '{value}'], [\DB::table($this->table), $fieldString, $valueString], 'INSERT INTO `{table}` {field} VALUES {value};');
        $this->initDb($sql);
        return $sql;
    }

    protected function structureUpdate(){
        if (!$this->table){ throw new \Exception('table is null');}
        if (!$this->data){ throw new \Exception('update the data is null');}
        if (!$this->where){ throw new \Exception('update data condition is null');}
        $params = [];
        $condition = str_replace(' where ', '', $this->getWhereStructure($params));
        foreach ($params as $param){
            $condition = str_replace(['%i', '%s', '%d'], [$param, "'{$param}'", intval($param)], $condition);
        }
        $flag = \DB::update($this->table, $this->data, $condition);
        $this->initDb();
        return $flag;
    }

    protected function insert(){
        if (!$this->table){ throw new \Exception('table is null');}
        if (!$this->data){ throw new \Exception('the insert data is null');}
        $insertId = \DB::insert($this->table, $this->data, true);
        $this->initDb();
        return $insertId;
    }

    protected function getWhereStructure(array &$params = []){
        $condition = '';
        foreach ($this->where as $item){
            $type = $item['type'];
            foreach ($item['condition'] as $value) {
                $value['value'] = $value['condition'] != 'like' ? $value['value'] : '%'.$value['value'].'%';
                $mark = is_int($value['value']) ? '%d' : (in_array($value['condition'], ['in', 'not in']) ? '%d' : '%s');
                $condition .= (strlen($condition) ? ' '.$type.' ' : ' where ').$value['key'].' '.$value['condition'].' '.$mark;
                $params[] = $value['value'];
            }
        }
        return $condition;
    }

    protected function delWhereStructures(){
        if (!$this->table){ throw new \Exception('table is null');}
        $params = [$this->table];
        $condition = $this->getWhereStructure($params);
        return ['params'=>$params, 'sql'=>'delete from %t'.$condition];
    }

    protected function delWhereStructure(){
        $condition = '';
        foreach ($this->where as $item){
            $type = $item['type'];
            foreach ($item['condition'] as $value) {
                $value['value'] = $value['condition'] != 'like' ? $value['value'] : '%'.$value['value'].'%';
                $mark = is_int($value['value']) ? '' : (in_array($value['condition'], ['in', 'not in']) ? '' : '\'');
                $condition .= (strlen($condition) ? ' '.$type.' ' : ' where ').$value['key'].' '.$value['condition'].' '.$mark.$value['value'].$mark;
            }
        }
        return $condition;
    }

    private function initDb($exec = ''){
        $this->where = $this->data = [];
        $this->field = $this->order = $this->limit = $this->group = null;
        $this->last = $exec;
        return $this;
    }
}